package com.atguigu.exam.service.impl;


import com.atguigu.exam.entity.ExamRecord;
import com.atguigu.exam.entity.Paper;
import com.atguigu.exam.entity.PaperQuestion;
import com.atguigu.exam.entity.Question;
import com.atguigu.exam.mapper.ExamRecordMapper;
import com.atguigu.exam.mapper.PaperMapper;
import com.atguigu.exam.mapper.PaperQuestionMapper;
import com.atguigu.exam.service.PaperQuestionService;
import com.atguigu.exam.service.PaperService;
import com.atguigu.exam.vo.PaperVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import kotlin.jvm.internal.Lambda;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 试卷服务实现类
 */
@Slf4j
@Service
public class PaperServiceImpl extends ServiceImpl<PaperMapper, Paper> implements PaperService {
    @Autowired
    private PaperQuestionService paperQuestionService;
    @Autowired
    private PaperQuestionMapper paperQuestionMapper;
    @Autowired
    private ExamRecordMapper examRecordMapper;

    //调用paperMapper根据id查询试卷详情的方法,写sql语句
    @Override
    public Paper getDetailsById(Integer id) {
        Paper paper = baseMapper.getDetailsById(id);
        return paper;
    }

    /**
     * 创建试卷
     * @param paperVo 试卷信息
     */
    @Override
    public void createPaper(PaperVo paperVo) {
        //判断创建的试卷是否已经存在
        boolean exists = baseMapper.exists(new LambdaQueryWrapper<Paper>().eq(Paper::getName, paperVo.getName()));
        if (exists){
            throw new RuntimeException("该试卷已经存在");
        }
        //创建Paper对象存储PaperVo对象试卷信息
        Paper paper = new Paper();
        //使用BeanUtils工具类将paperVo对象属性复制给paper对象
        BeanUtils.copyProperties(paperVo,paper);
        //设置当前试卷状态为草稿
        paper.setStatus("DRAFT");
        //获取当前试卷所有题目
        Map<Integer, BigDecimal> questions = paperVo.getQuestions();
        //计算当前试卷的总分
        BigDecimal reduce = questions.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        //设置当前试卷的总分
        paper.setTotalScore(reduce);
        //设置当前试卷的题目数量
        int size = questions.size();
        //设置当前试卷的题目数量
        paper.setQuestionCount(size);
        //保存试卷
        baseMapper.insert(paper);
        //往中间表插入数据
        //将Map<Integer,BigDecimal>转成为Map<PaperQuestion>  试卷保存完,再保存该试卷的相关题目
        List<PaperQuestion> collect = questions.entrySet().stream().map(entry -> {
            //该 Lambda 表达式的输入参数是 entry，类型为 Map.Entry<Integer, BigDecimal>
            //这个 entry 代表 questions 这个 Map<Integer, BigDecimal> 中的每一个键值对条目
            //Lambda 表达式的作用是将每个 Map.Entry<Integer, BigDecimal> 转换为一个 PaperQuestion 对象
            PaperQuestion paperQuestion = new PaperQuestion(paper.getId(), entry.getKey().longValue(), entry.getValue());
            return paperQuestion;
        }).collect(Collectors.toList());
        //往中间表中批量添加数据
        paperQuestionService.saveBatch(collect);
    }

    /**
     * 修改试卷
     * @param id 试卷id
     * @param paperVo 试卷信息
     */
    @Override
    public void updatePaper(Integer id, PaperVo paperVo) {
        //根据id查询试卷
        Paper paper = baseMapper.selectById(id);
        //判断该试卷是否已发布,发布状态的试卷不能修改
        if ("PUBLISHED".equals(paper.getStatus())){
            throw new RuntimeException("该试卷已发布,不能修改");
        }
        //判断修改之后的试卷是否存在
        boolean exists = baseMapper.exists(new LambdaQueryWrapper<Paper>().eq(Paper::getName, paperVo.getName()).ne(Paper::getId,id));
        if (exists){
            throw new RuntimeException("该试卷已经存在");
        }
        //使用BeanUtils工具类将paperVo对象属性复制给question对象
        BeanUtils.copyProperties(paperVo,paper);
        //获取修改之后的试卷所有题目
        Map<Integer, BigDecimal> questions = paperVo.getQuestions();
        //计算修改之后的试卷总分
        BigDecimal reduce = questions.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        //设置修改之后的试卷总分
        paper.setTotalScore(reduce);
        //获取修改之后的试卷所有题目数量
        int size = questions.size();
        //设置修改之后的试卷题目数量
        paper.setQuestionCount(size);
        //修改试卷
        baseMapper.updateById(paper);
        //删除中间原来的数据
        paperQuestionMapper.delete(new LambdaQueryWrapper<PaperQuestion>().eq(PaperQuestion::getPaperId, id));
        //往中间便插入数据
        //将Map<Integer,DigDecimal>类型转换成List<PaperQuestion>类型,便于后续的批量操作和数据处理
        List<PaperQuestion> collect = questions.entrySet().stream().map(entry -> {
            PaperQuestion paperQuestion = new PaperQuestion(paper.getId(), entry.getKey().longValue(), entry.getValue());
            return paperQuestion;
        }).collect(Collectors.toList());
        //调用paperQuestionService批量保存数据的方法(paperQuestionMapper中没有批量保存的方法)
        paperQuestionService.saveBatch(collect);
    }

    @Override
    public void deletePaper(Integer id) {
        //判断要删除的试卷是否已发布
        Paper paper = baseMapper.selectById(id);
        //发布状态的试卷不能删除
        if ("PUBLISHED".equals(paper.getStatus())){
            throw new RuntimeException("该试卷已发布,不能删除");
        }
        //判断要删除的试卷是否有考试记录
        Long count = examRecordMapper.selectCount(new LambdaQueryWrapper<ExamRecord>().eq(ExamRecord::getExamId, id));
        if (count>0){
            throw new RuntimeException("该试卷有考试记录,不能删除");
        }
        //删除试卷
        baseMapper.deleteById(id);
        //删除中间表的数据
        paperQuestionMapper.delete(new LambdaQueryWrapper<PaperQuestion>().eq(PaperQuestion::getPaperId,id));
    }

    @Override
    public void updatePaperStatus(Integer id, String status) {
        //获取要修改的试卷
        Paper paper = baseMapper.selectById(id);
        //判断要修改的试卷是否已发布
        Long Count = examRecordMapper.selectCount(new LambdaQueryWrapper<ExamRecord>().eq(ExamRecord::getExamId, id).eq(ExamRecord::getStatus, "进行中"));
        if (Count>0){
            throw new RuntimeException("该试卷有进行中的考试记录,不能修改状态");
        }
        //更新试卷的状态
        baseMapper.update(paper,new LambdaUpdateWrapper<Paper>().eq(Paper::getId,id).set(Paper::getStatus,status));
    }
}